#include <ConnectionBroker/clientconnection/ClientConnection.h>
#include <ConnectionBroker/server/Server.h>
#include <ConnectionBroker/Channels.h>
#include <ConnectionBroker/PacketUtils.h>
#include <json/json.h>

using namespace ConnectionBroker;

Server::Server(const ServerSettings& settings, 
               serverCallback pDefaultMessageCallback, 
               serverCallback pDefaultClientConnectCallback,
               serverCallback pDefaultClientDisconnectCallback
               )
: mSettings(settings), 
  mAppOnMessageCallback(pDefaultMessageCallback), 
  mAppOnClientConnectCallback(pDefaultClientConnectCallback), 
  mAppOnClientDisconnectCallback(pDefaultClientDisconnectCallback), 
  mOnMessageCallback(NULL), 
  mOnClientConnectCallback(NULL),
  mOnClientDisconnectCallback(NULL)
{
}

Server::~Server()
{
}

void Server::addClient(ClientConnectionPtr pClient)
{
   boost::mutex::scoped_lock l(mMutex);
   mClients.insert(pClient);
   Json::Value val;
   Packet pPacket(0, val);

   if(mAppOnClientConnectCallback)
      mAppOnClientConnectCallback(shared_from_this(), pClient, pPacket);

   if(mOnClientConnectCallback)
      mOnClientConnectCallback(shared_from_this(), pClient, pPacket);
}

void Server::messageReceived(ClientConnectionPtr pSender, const std::string& pMessage, const uint32_t pChannel)
{
   Packet pPacket(pChannel, PacketUtils::stringToJson(pMessage));
   messageReceived(pSender, pPacket);
}

void Server::messageReceived(ClientConnectionPtr pSender, const std::string& pMessage)
{
   Packet pPacket(PacketUtils::stringToPacket(pMessage));
   messageReceived(pSender, pPacket);
}

void Server::messageReceived(ClientConnectionPtr pSender, const Packet& pPacket)
{
   if(!pPacket.channel() || pPacket.message().isNull())
      return;

   if(mAppOnMessageCallback)
      mAppOnMessageCallback(shared_from_this(), pSender, pPacket);

   //Return early if we're on a library channel.
   if(pPacket.channel() <= Channels::PREDEFINED_MAX)
      return;

   if(mOnMessageCallback)
      mOnMessageCallback(shared_from_this(), pSender, pPacket);
}

void Server::removeClient(ClientConnectionPtr pClient)
{
   if(!pClient)
      return;

   boost::mutex::scoped_lock l(mMutex);
   int erased = mClients.erase(pClient);
}

void Server::removeOnMessageCallback()
{
   mOnMessageCallback = NULL;
}

void Server::setOnClientConnectCallback(serverCallback pCallback)
{
   mOnClientConnectCallback = pCallback;
}

void Server::setOnClientDisconnectCallback(serverCallback pCallback)
{
   mOnClientDisconnectCallback = pCallback;
}

void Server::setOnMessageCallback(serverCallback pCallback)
{
   mOnMessageCallback = pCallback;
}

void Server::write(ClientConnectionPtr pRecipient, const Packet& pMessage)
{
   //Ensure the client is subscribed to this channel.
   if(!pRecipient->subscribedTo(pMessage.channel()))
   {
      std::cout << pRecipient << " is not subscribed to " << pMessage.channel() << std::endl;
      return;
   }

   std::cout << "WRITE" << std::endl;
   std::cout << pMessage.message() << std::endl;

   pRecipient->write(pMessage);
}

void Server::writeToAll(const Packet& pMessage)
{
   std::set<ClientConnectionPtr> pClients;
   {
      boost::mutex::scoped_lock l(mMutex);
      pClients = mClients;
   }

   for(std::set<ClientConnectionPtr>::iterator it = pClients.begin(); it != pClients.end(); ++it)
      write(*it, pMessage);
}

uint32_t Server::numberOfClientsSubscribedTo(const uint32_t channelNumber)
{
   std::set<ClientConnectionPtr> pClients;
   {
      boost::mutex::scoped_lock l(mMutex);
      pClients = mClients;
   }

   uint32_t numClients = 0;
   for(std::set<ClientConnectionPtr>::iterator it = pClients.begin(); it != pClients.end(); ++it)
   {
      if(!(*it)->subscribedTo(channelNumber))
         continue;

      numClients++;
   }

   return numClients;
}

